package com.szwistar.common.comm.jsonrpc.http;

import com.hibegin.http.server.impl.HttpRequest;
import com.hibegin.http.server.impl.HttpResponse;
import com.hibegin.http.server.util.HttpMethod;
import com.hibegin.http.server.web.Controller;
import com.szwistar.common.ERR;
import com.szwistar.common.comm.jsonrpc.JsonRpcEndpointAbstract;
import com.szwistar.common.comm.jsonrpc.JsonRpcMessage;
import com.szwistar.common.comm.jsonrpc.JsonRpcMessageCall;
import com.szwistar.common.comm.jsonrpc.JsonRpcMessageNotify;
import com.szwistar.common.comm.jsonrpc.JsonRpcMessageReturn;
import com.szwistar.common.datastruct.JsonMapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * JsonRpc over HTTP 服务
 * @author 张勇
 * <p>例如：调用网关侧上的服务
 * <pre>
 * 1. http://localhost:9404/jsonRpc/call?method=app.callApi&params={"oid":0, "api":"tts", "params":["你好", "xiaoyan", 50, 50, 50]}
 * 2. http://localhost:9404/jsonRpc/call?method=app.doAction&params={"id":228}
 * 3. ...&params={"oid":280,"api":"config","params":["{\"manufactory\":\"爱家乐\",\"model\":\"AR-RAE6C\",\"groupIndex\":12932}"]}
 *	第三点特此注明： 如果params里面有参数为json的字符串的话 需要将json对象转为字符串 在放到params的数组中 否则就会出现找不到method的问题
 *	PS:“params":[{"manufactory":"爱家乐","model":"AR-RAE6C","groupIndex":12932}] 为错误示范
 * </pre>
 * </p>
 */
public class WebController4JsonRpc extends JsonRpcEndpointAbstract implements Controller {
	protected static final Logger LOG = LoggerFactory.getLogger(WebController4JsonRpc.class);

	// 待返回的结果
	protected Map<String, HttpResponse> pendingResponse = new ConcurrentHashMap<String, HttpResponse>();

	/**
	 * 远程Web应用通过 JsonRpc@HTTP 调用本端Web服务器中注册的 JsonRpc 服务
	 */
	public void call(HttpRequest request, HttpResponse response) {
		JsonRpcMessageCall rpcRequest = null;

		if(request.getMethod() == HttpMethod.GET) {
			// 取出调用参数
			rpcRequest = new JsonRpcMessageCall();
			rpcRequest.setToken (request.getParaToStr("token" , ""));
			rpcRequest.setMethod(request.getParaToStr("method", null));
			rpcRequest.setParams(request.getParaToStr("params", ""));
		}
		else if(request.getMethod() == HttpMethod.POST) {
			try {
	            // 消息解码
				String json = request.getBodyText();
				rpcRequest = JsonMapper.fromJson(json, JsonRpcMessageCall.class);
			} catch (Exception e) {
				response.renderCode(ERR.BAD_PARAM, "JsonRpc over HTTP/POST 接收消息解码失败！<br>" + e.getMessage());
				return;
			}
		}
		else {
			response.renderCode(ERR.COMMAND, "JsonRpc@HTTP 不支持 HTTP 方法: " + request.getMethod().name());
			return;
		}

		// !!!注意：属于 P2P 类型的连接，一定要替换消息中的客户端标识!!!
		rpcRequest.setFrom(request.getRemoteHost().toString().substring(1));

		// 把 response 放入等待队列
		pendingResponse.put(rpcRequest.getFrom(), response);

		// 交给父类处理，处理完成之后，会异步调用下面的 send() 函数返回结果
		onMessageReceived(rpcRequest);
	}

	@Override
	public void send(String target, JsonRpcMessage msg, int qos) {
		// 从等待队列中取出(并删除)异步请求
		HttpResponse response = pendingResponse.get(target); pendingResponse.remove(target);
		if(response == null) {
			LOG.warn("异步请求已经超时，结果被丢弃！");
			return;
		}
		// 返回结果
		response.renderJson(msg);
	}

	/**
	 * 远程Web应用通过 JsonRpc@HTTP 通知本端Web服务器中注册的 JsonRpc 接口
	 */
	public void notify(HttpRequest request, HttpResponse response) {
		JsonRpcMessageNotify rpcRequest = null;

		if(request.getMethod() == HttpMethod.GET) {
			// 取出调用参数
			rpcRequest = new JsonRpcMessageNotify();
			rpcRequest.setToken (request.getParaToStr("token" , ""));
			rpcRequest.setMethod(request.getParaToStr("method", null));
			rpcRequest.setParams(request.getParaToStr("params", ""));
		}
		else if(request.getMethod() == HttpMethod.POST) {
			try {
	            // 消息解码
				String json = request.getBodyText();
				rpcRequest = JsonMapper.fromJson(json, JsonRpcMessageNotify.class);
			} catch (Exception e) {
				response.renderCode(ERR.BAD_PARAM, "JsonRpc over HTTP/POST 接收消息解码失败！<br>" + e.getMessage());
				return;
			}
		}
		else {
			response.renderCode(ERR.COMMAND, "JsonRpc@HTTP 不支持 HTTP 方法: " + request.getMethod().name());
			return;
		}

		// !!!注意：属于 P2P 类型的连接，一定要替换消息中的客户端标识!!!
		rpcRequest.setFrom(request.getRemoteHost().toString().substring(1));

		// 交给父类处理，无需等待返回结果
		onMessageReceived(rpcRequest);
	}

	@Override
	public JsonRpcMessageReturn handleSubscribe(JsonRpcMessageCall request) {
		return JsonRpcMessageReturn.error(request, ERR.NOT_SUPPORT, "JsonRpc@HTTP 不支持消息订阅！");
	}

	@Override
	public void listenOn(Object linkObj, String caller) throws Exception {
		// do nothing
	}

	@Override
	public boolean isConnected() {
		return false;
	}

	@Override
	public void close() {
		// do nothing
	}
}
